/*
 * DvmDex.c
 *
 *  Created on: 2011-7-15
 *      Author: gexiao
 */
/*
 * VM-specific state associated with a DEX file.
 */
#include "Dalvik.h"

#include <sys/types.h>
#include <unistd.h>

/*
 * Create auxillary data structures.
 *
 * We need a 4-byte pointer for every reference to a class, method, field,
 * or string constant. Summed up over all loaded DEX files (including the
 * whoppers in the bootstrap class path), this adds up to be quite a bit
 * of native memory.
 *
 * For more traditional VMs these values could be stuffed into the loaded
 * class file constant pool area, but we don't have that luxury since our
 * classes are memory-mapped read-only.
 *
 * The DEX optimizer will remove the need for some of these (e.g. we won't
 * use the entry for virtual methods that are only called through
 * invoke-virtual-quick), creating the possibility of some space reduction
 * at dexopt time.
 */
static DvmDex* allocateAuxStructures(DexFile* pDexFile) {
	DvmDex* pDvmDex;
	const DexHeader* pHeader;

	pDvmDex = (DvmDex*) calloc(1, sizeof(DvmDex));
	if (pDvmDex == NULL)
		return NULL;

	pDvmDex->pDexFile = pDexFile;
	pDvmDex->pHeader = pDexFile->pHeader;

	pHeader = pDvmDex->pHeader;

	pDvmDex->pResStrings = (struct StringObject**) calloc(
			pHeader->stringIdsSize, sizeof(struct StringObject*));

	pDvmDex->pResClasses = (struct ClassObject**) calloc(pHeader->typeIdsSize,
			sizeof(struct ClassObject*));

	pDvmDex->pResMethods = (struct Method**) calloc(pHeader->methodIdsSize,
			sizeof(struct Method*));

	pDvmDex->pResFields = (struct Field**) calloc(pHeader->fieldIdsSize,
			sizeof(struct Field*));

	pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);

	if (pDvmDex->pResStrings == NULL || pDvmDex->pResClasses == NULL
			|| pDvmDex->pResMethods == NULL || pDvmDex->pResFields == NULL
			|| pDvmDex->pInterfaceCache == NULL) {
		free(pDvmDex->pResStrings);
		free(pDvmDex->pResClasses);
		free(pDvmDex->pResMethods);
		free(pDvmDex->pResFields);
		free(pDvmDex);
		return NULL;
	}

	return pDvmDex;
}

/*
 * Given an open optimized DEX file, map it into read-only shared memory and
 * parse the contents.
 *
 * Returns nonzero on error.
 */
int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex) {
	DvmDex* pDvmDex;
	DexFile* pDexFile;
	MemMapping memMap;
	int result = -1;
	if (lseek(fd, 0, SEEK_SET) < 0) {
		goto bail;
	}

	//if (sysMapFileInShmem(fd, &memMap) != 0) {
		//goto bail;
	//}
	pDexFile = dexFileParse(memMap.addr, memMap.length);
	if (pDexFile == NULL) {
		sysReleaseShmem(&memMap);
		goto bail;
	}

	pDvmDex = allocateAuxStructures(pDexFile);
	if (pDvmDex == NULL) {
		dexFileFree(pDexFile);
		sysReleaseShmem(&memMap);
		goto bail;
	}

	//tuck this into the DexFile so it gets released later
	sysCopyMap(&pDvmDex->memMap, &memMap);
	*ppDvmDex = pDvmDex;
	result = 0;

	bail: return result;
}

/*
 * Free up the DexFile and any associated data structures.
 *
 * Note we may be called with a partially-initialized DvmDex
 */
void dvmDexFileFree(DvmDex* pDvmDex) {
	if (pDvmDex == NULL)
		return;

	dexFileFree(pDvmDex->pDexFile);

	free(pDvmDex->pResStrings);
	free(pDvmDex->pResClasses);
	free(pDvmDex->pResMethods);
	free(pDvmDex->pResFields);
	dvmFreeAtomicCache(pDvmDex->pInterfaceCache);

	sysReleaseShmem(&pDvmDex->memMap);
	free(pDvmDex);
}

